<?php

	/**
     * Locale
     *
	 * Static class to get a localized string
	 *
	 * @package      Core
	 * @subpackage   Locale
     *
     * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
	 */
	class Core_Locale extends Core_Object
    {

	////////////////////////////////////////////////////////////////////////////
	//                                Variables                               //
	////////////////////////////////////////////////////////////////////////////

        /**
		 * Locale
		 *
		 * @var Zend_Locale
		 */
		protected $_locale = null;

        /**
        * Array indexed by locale/module name, containing the translations
        * @var array
        */
        protected $_bundles = array();

		/**
		 * Zend_Registry object
		 *
		 * @var Zend_Registry
		 */
		protected $_registry = null;

        /**
         * Singleton instance
         *
         * Marked only as protected to allow extension of the class.
         * To extend, simply override {@link getInstance()}.
         *
         * @var Core_Locale
         */
        protected static $_instance = null;

	////////////////////////////////////////////////////////////////////////////
	//                            Getters / Setters                           //
	////////////////////////////////////////////////////////////////////////////

        /**
        * Returns the language part of the locale
        *
        * @throws		Core_Exception
        * @return       string
        */
        public function getCurrentLang()
        {
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			$lang = '';
            if (!($lang = $this->_locale->getLanguage())) {
				$locale = explode('_', $this->_registry['config']->view->locale);
				$lang = $locale[0];
			}

            return $lang;
        }

        /**
        * Returns the region part of the locale (ISO code on 2 characters)
        *
        * @throws		Core_Exception
        * @return       string
        */
        public function getCurrentCountry()
        {
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			$iso = '';
            if (!($iso = $this->_locale->getRegion())) {
				$locale = explode('_', $this->_registry['config']->view->locale);
				$iso = $locale[1];
			}

            return $iso;
        }

        /**
        * Returns the region part of the locale (ISO code on 2 characters)
        *
        * @throws		Core_Exception
        * @return       string
        */
		public function getLocale()
		{
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			if ($locale = $this->_locale->getRegion()) {
				return $this->_locale->getLanguage() .'_'. $locale;
			} else {
				return $this->_registry['config']->view->locale;
			}
		}

		/**
		 * Retrieve ISO date format
		 *
		 * @param		string		$type
		 * @throws		Core_Exception
		 * @return		string
		 */
		public function getDateFormat($type = null)
		{
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			return $this->_locale->getTranslation($type, 'date');
		}

		/**
		 * Retrieve ISO time format
		 *
		 * @param		string		$type
		 * @throws		Core_Exception
		 * @return		string
		 */
		public function getTimeFormat($type = null)
		{
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			return $this->_locale->getTranslation($type, 'time');
		}

		/**
		 * Retrieve ISO datetime format
		 *
		 * @param		string		$type
		 * @throws		Core_Exception
		 * @return		string
		 */
		public function getDateTimeFormat($type)
		{
			if (!($this->_locale instanceof Zend_Locale)) {
				throw new Core_Exception('Fatal error: locale isn\'t an instance of Zend_Locale.');
			}

			return $this->getDateFormat($type) . ' ' . $this->getTimeFormat($type);
		}

	////////////////////////////////////////////////////////////////////////////
	//                             Static Methods                             //
	////////////////////////////////////////////////////////////////////////////

        /**
         * Singleton instance
         *
         * @param       boolean     $reset : true to force to re-instancy the locale
         * @return      Core_Controller_Coordinator
         */
        public static function getInstance($reset = false)
        {
            if ($reset) {
                self::$_instance = null;
            }

            if (self::$_instance === null) {
                self::$_instance = new self();
            }

            return self::$_instance;
        }

	////////////////////////////////////////////////////////////////////////////
	//                                 Methods                                //
	////////////////////////////////////////////////////////////////////////////

        /**
		 * Constructor
		 */
		public function __construct()
        {
			$this->_registry	= Zend_Registry::getInstance();
			$this->_locale		= new Zend_Locale($this->_registry['config']->view->locale);
        }

		/**
		 * Destructor
		 */
		public function __destruct()
		{
			unset($this);
		}

        /**
         * Gets all bundles for current language.
         *
         * @param       array           $modules : modules list
         * @param       string          $locale : the language code. If null, use the default language
         * @return      array
         */
        public function getBundles(array $modules = array(), $locale = null)
        {
            foreach($modules as $toloadModule) {
                // Init bundles
                $selector = new Core_Selector_Locale($toloadModule .'~init', $locale);

                $locale = $selector->getLocale();
                $module = $selector->getModule();
                $messageKey = $selector->getMessageKey();

                if (!array_key_exists($locale, $this->_bundles)) {
                    $this->_bundles[$locale] = array();
                }

                if (!array_key_exists($module, $this->_bundles[$locale])) {
                    $this->_bundles[$locale][$module] = Core_Locale_Compiler::get($selector, $locale);
                }
            }

            return $this->_bundles[$locale];
        }

        /**
        * Gets the correct string, for a given language.
        *   if it can't get the correct language, it will try to gets the string
        *   from the default language.
        *   If both fails, it will raise an exception.
        *
        * @param        string          $key : the key of the localized string
        * @param        array|string    $args : arguments to apply to the localized string with sprintf
        * @param        string          $locale : the language code. If null, use the default language
        * @throws		Core_Exception
        * @throws		Core_ArgumentException
        * @throws		Core_ArgumentNullException
        * @return       string          the localized string
        */
        public function translate($key, $args = null, $locale = null)
        {
            if ($key === null) {
				throw new Core_ArgumentNullException('key is a null reference');
			}

            if (strlen(trim($key)) == 0) {
				throw new Core_ArgumentException('key is a zero-length string');
			}

            $selector = new Core_Selector_Locale($key, $locale);

            $locale = $selector->getLocale();
            $module = $selector->getModule();
            $messageKey = $selector->getMessageKey();

            if (!array_key_exists($locale, $this->_bundles)) {
                $this->_bundles[$locale] = array();
            }

            if (!array_key_exists($module, $this->_bundles[$locale])) {
                $this->_bundles[$locale][$module] = Core_Locale_Compiler::get($selector, $locale);
            }

            $string = '';

            // try to get the message from the bundle
            if (array_key_exists($messageKey, $this->_bundles[$locale][$module])) {
                $string = $this->_bundles[$locale][$module][$messageKey];
            } else {
                //if the message wasn't found, we use the default language and country
                if (!array_key_exists($this->_registry['config']->view->locale, $this->_bundles) || !array_key_exists($module, $this->_bundles[$this->_registry['config']->view->locale])) {
                    return $this->translate($key, $args, $this->_registry['config']->view->locale);
                } else {
                    if (array_key_exists($messageKey, $this->_bundles[$this->_registry['config']->view->locale][$module])) {
                        $string = $this->_bundles[$this->_registry['config']->view->locale][$module][$messageKey];
                    } else {
                        if ($this->_registry['config']->debug == true) {
                            return $messageKey;
                        } else {
                            throw new Core_Exception('The given locale key "'. $messageKey .'" does not exists in the default language.');
                        }
                    }
                }
            }

            // inject arguments in the string
            if ($args !== null) {
                $string = call_user_func_array('sprintf', array_merge(array($string), is_array($args) ? $args : array ($args)));
            }

            return $string;
        }
    }
